package com.prac.redis.controller;

import com.alibaba.fastjson.JSON;
import com.prac.common.result.DataResult;
import com.prac.redis.pojo.User;

import java.util.List;
import java.util.Set;
import java.util.UUID;
import javax.annotation.Resource;

import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author hxg
 * @version 1.0
 * @date 2022/4/29 19:49
 */
@RestController
@Slf4j
public class TestSecKill {

    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    /**
     * 初始化redis库存数据
     */
    @RequestMapping("/test")
    public User init() {
        User user = new User(1, "hhh这里", 21);
        System.out.println(user);
        //存入redis时先做了把对象转换成json
        redisTemplate.opsForValue().set("user用户", JSON.toJSONString(user));
        redisTemplate.opsForValue().set("sk:1001:qt测试", "10");
        User redisUser = JSON.parseObject(String.valueOf(redisTemplate.opsForValue().get("user用户")), User.class);
        return redisUser;
    }

    /**
     * linux下用 ab 对单接口压测，模拟多并发 （简单的DDOS攻击） ab -i -n 2000 -c 200 http://192.168.31.228:9090/seckill
     *
     * @return
     */
    @GetMapping("/seckill")
    public DataResult<Boolean> secKill() {
        String uid = UUID.randomUUID().toString().substring(1, 10);
        Boolean flag = doSecKill(uid);
        if (flag) {
            log.info("{}-秒杀成功", Thread.currentThread().getId());
            return new DataResult<>(true);
        } else {
            log.info("{}-秒杀成功", Thread.currentThread().getId());
            return new DataResult<>(false);
        }

    }

    private Boolean doSecKill(String uid) {
        if (uid == null) {
            return false;
        }
        String skUser = "sk:user:" + uid;
        String skQt = "sk:qt:1001";

        //开启监视
        redisTemplate.watch(skQt);

        //库存判断
        //1 库存为空（未开始秒杀） 2 库存为0（秒杀结束）
        String redisQt = String.valueOf(redisTemplate.opsForValue().get(skQt));
        if (redisQt == null || Integer.parseInt(redisQt) <= 0) {
            log.info("========秒杀结束======");
            return false;
        }
        //是否重复抢购
        Set<Object> members = redisTemplate.opsForSet().members(skUser);
        if (!members.isEmpty()) {
            return false;
        }
        //记录库存、秒杀成功人员
        //开启事务防止多线程情况下 其它请求影响当前redis命令
        redisTemplate.setEnableTransactionSupport(true);
        try {
            redisTemplate.multi();

            redisTemplate.opsForValue().decrement(skQt);
            redisTemplate.opsForSet().add(skUser, uid);

            List<Object> execList = redisTemplate.exec();
            if (execList.isEmpty()) {
                return false;
            }
        } catch (Exception e) {
            //开启回滚
            redisTemplate.discard();
        }
        return true;
    }

}
